package com.eeb.dropwizardmongo.example.resources;

import com.codahale.metrics.annotation.Timed;
import com.eeb.dropwizardmongo.example.api.History;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.mongojack.DBQuery;
import org.mongojack.DBUpdate;
import org.mongojack.JacksonDBCollection;

import javax.validation.Valid;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.util.Map;

@Path("/history")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class HistoryResource {

    private JacksonDBCollection<History, String> history;

    public HistoryResource(JacksonDBCollection<History, String> history) {
        this.history = history;
    }

    @GET
    @Produces(value = MediaType.APPLICATION_JSON)
    @Timed
    public Response getAllHistory(@QueryParam("history") String history) throws UnsupportedEncodingException {
        DBQuery.Query query = DBQuery.empty();
        if (history != null)
            query = history.startsWith("-") ?
                    query.nor(DBQuery.all("history", URLEncoder.encode(history.substring(1), "UTF-8"))) :
                    query.all("history", URLEncoder.encode(history, "UTF-8"));
        return Response.ok(this.history.find(query).toArray()).build();
    }

    @Path("/{history}")
    @GET
    @Produces(value = MediaType.APPLICATION_JSON)
    @Timed
    public Response getHistory(@PathParam("history") String history) {
        return Response.ok(this.history.findOne(DBQuery.is("name", history))).build();
    }

    @POST
    @Timed
    public Response postHistory(@Valid History history) throws URISyntaxException, UnsupportedEncodingException {
        URI uri = new URI("/" + history.getName());
        if (this.history.findOne(DBQuery.is("name", history.getName())) == null)
            this.history.insert(history);
        return Response.created(uri).entity(this.history.findOne(DBQuery.is("name", history.getName()))).build();
    }

    @PUT
    @Timed
    public Response putHistory(@Valid History History) {
        return Response.status(405).entity("PUT to /history/{name} or POST to /history").build();
    }

    @Path("/{history}")
    @PUT
    @Timed
    public Response putHistory(@PathParam("history") String history,
                               @Valid String json) throws IOException {
        DBQuery.Query query = DBQuery.is("name", history);
        Map<String, Object> map = new ObjectMapper().readValue(json, new TypeReference<Map<String, Object>>() {
        });
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            if (entry.getValue() != null) {
                this.history.update(query, DBUpdate.set(entry.getKey(), entry.getValue()));
            }
        }
        return Response.ok(this.history.findOne(DBQuery.is("name", history))).build();
    }

    @Path("/{history}")
    @DELETE
    @Timed
    public Response deleteHistory(@PathParam("history") String history) {
        this.history.findAndRemove(DBQuery.is("name", history));
        return Response.ok(this.history.find().toArray()).build();
    }

}